                   Introducing PrintDLL.DLL

     PrintDIB.DLL and this document Copyright (c) 1996 ASL
                      All Rights Reserved

While working on a Delphi program we ran across a Canon printer driver 
that was troublesome. It wouldn't allow us to use the standard Delphi 
StretchDraw. Why? Well, it appears that StretchDraw is a wrapper for 
StrecthBlt(), and an increasing number of printer drivers (including 
the new Canon driver we tested with) won't support StretchBlt() 
although they will work OK with StretchDIBits. 

Moreover, we had an older VB product that was also having the same 
problem (it used StretchBlt() as well) on the new printer drivers, 
so we decided that the best solution was to write a DLL that would 
allow VB _and_ Delphi the same functionality. We used Borland's C++ 
(V 3.1) to create the DLL with, so this will work on Windows, 
Windows for Workgroups, and Windows95. (It's 16 bit.)

Working with DIBs and BITMAPINFOHEADER and all that stuff is, well, 
confusing to a lot of us. The worst part is that the only place in the 
typical app that the DIB code is needed for stretching is the printer, 
so you wind up with a lot of code lying around that doesn't get used 
very much. (We have yet to see a video driver that wouldn't work with
StretchBlt.)

What PrintDLL does is take your bitmap information, turn it into a DIB, 
and then outputs the DIB to the printer. Printer drivers that choke on 
Delphi's StretchDraw are now able to accept your stretched bitmaps, and 
you don't have to write volumes of DIB handling code just to stretch a 
standard bitmap out to your printer. 

PrintDLL is suitable for doing labels, desktop publishing, paint programs, 
or any other program that needs to output a bitmap on the printer in a 
specific area and at a specific size. The Delphi 1.0 example code below 
works OK and as you can see, it isn't exactly huge. Nor is the VB3 example 
that is enclosed inside this ZIP.

Caveats: As far as we know this won't work on network drives. Your mileage 
may vary. If it does, well, great. :-)

Can you do what PrintDLL does yourself? Of course you can. However, you 
need to factor how long it would take you to do this vs. what it costs 
to buy PrintDLL, which you basically plug in. PrintDLL costs far less than 
one hour of your time, and it can be used in any project written with any 
language that can call a DLL.

PrintDLL is shareware. That means you get to play with it as needed to see 
if you want to use it in your application. If you do, you'll need to buy it. 
To purchase PrintDLL, call 1-800-242-4775 and order PrintDLL as product 
number 15031. Alternately (outside the USA) you can call +1-713-524-6394 or
fax +1-713-524-6398 or send email with your card info to 
71355.470@compuserve.com (alternately you can access order services via the
PsL web site at www.pslweb.com.) Please let them know what your email address
is! When you order it, please also send an email to us. When we receive the
notification via email from PsL, we send the non-shareware version (i.e. the
shareware version doesn't put up the message box) to your email address.

PrintDLL is $16 US, and the preferred form of sending it is to your email 
address. (It's a small ZIP file.) If you prefer to send a check or a company
Purchase Order, mail it to:

ASL
P.O. Box 581
Ruidoso NM 88345
email asl@itctel.com

Please specify PRINTDLL as part #15031 on your P.O. If you want it to come
via snail mail on a disk, please specify this.

Restrictions: ASL makes no claim for fitness of purpose and makes no warranty 
of any kind. You may not license out PrintDLL to others as a DLL, although 
you can use it in your applications, commercial or otherwise. 

****************************************************************************


DELPHI EXAMPLE OF USING PRINTDLL:

{ put this right after IMPLEMENTATION in the module you will use }

procedure stretchedoutput(phwnd: HWND; printDC: HDC;
          hbmp: HBITMAP; hpal: HPalette;
          Xpos: Integer; Ypos: Integer;
          swidth: Integer;  sheight: integer); far; external 'PRINTDIB';
(*
 
   phwnd -- the Form.Handle of the Form that you are printing from.
            [ this is not required in the non-shareware version ]
   printDC -- the printer DC
   hbmp -- your bitmap handle to convert to a dib
   hpal -- the color palette to use; PRINTDLL works with 256 colors too
   xpos and ypos -- the upper left coordinate on the page of where the 
                    bitmap is going
   swidth and sheight -- the size in printer pixels of the printed bitmap

)*


{ This procedure assumes that you have a TBitmap named mybitmap.
  Note that the HWND parameter used in the stretchedoutput() call 
  assumes Form1.Handle. You will need to change these as needed for 
  your application. }

procedure TestPrintDLL;
var
     hmemdc,
     prdc:                   THandle;
     cprn: array[0..63] of   Char;
     cdev: array[0..63] of   Char;
     cdrv: array[0..63] of   Char;
     cop: array[0..63] of    Char;
     achar:                  Char;
     index, drvindex, j,
     i, tst:                 Integer;
     prnbitmap:              HBITMAP;
     mypalette:              HPalette;
begin
     {************************************************************}
     {                        STEP 1                              }
     {    PARSE THE WIN.INI SETTING TO GET THE PRINTER DRIVER     }
     {    AND CREATE A DC TO USE.                                 }
     {************************************************************}
     for i := 0 to 63 do begin
         cprn[i] := chr(0);
         cdev[i] := chr(0);   { no memset() in Delphi. Do this the }
         cdrv[i] := chr(0);   { hard way... :-( }
         cop[i] := chr(0);
     end;
     { Get the "device=" string in win.ini. This is where the info
       regarding the printer setup lives. }
     GetProfileString('Windows','device','',cprn,64);
     { now parse the resulting string }
     index := 0;
     repeat
       achar := cprn[index];
       if(achar <> ',') then begin
          cdev[index] := achar;
          inc(index);
       end;
     until achar = ',';
     inc(index);
     drvindex := 0;
     repeat
       achar := cprn[index];
       if(achar <> ',') then begin
          cdrv[drvindex] := achar;
          inc(drvindex);
          inc(index);
       end;
     until achar = ',';
     inc(index);
     drvindex := 0;
     repeat
       achar := cprn[index];
       if(achar <> chr(0)) then begin
          cop[drvindex] := achar;
          inc(drvindex);
          inc(index);
       end;
     until achar = chr(0);
     { Try to create a printer DC based on this info. }
     prdc := CreateDC(cdrv,cdev,cop,NIL);
     { Die if no printer DC -- but warn user first.  }
     if(prdc < 1) then begin
        messagedlg('Cannot create a printer DC.',
                    mtwarning, [mbok], 0);
        exit;
     end;

     {************************************************************}
     {                        STEP 2                              }
     {       USE CreateCompatibleDC TO OBTAIN AN HBITMAP          }
     {************************************************************}

     { create a memory DC }
     hmemdc := CreateCompatibleDC(mybitmap.canvas.handle);
     { create a bitmap ... prnbitmap := HBitmap }
     prnbitmap := CreateCompatibleBitmap(mybitmap.canvas.handle,
                                         mybitmap.width,
                                         mybitmap.height);
     { make sure to copy the palette over }
     mypalette := mybitmap.canvas.palette;
     SelectObject(hmemdc, prnbitmap);
     SelectPalette(hmemdc, mypalette, TRUE);
     { get the bitmap into the memory DC }
     BitBlt(hmemdc, 0, 0, mybitmap.width, mybitmap.height,
            mybitmap.canvas.handle, 0, 0, SRCCOPY);
     { The string 'TESTPRINT' is the document name, and it's 9 chars long.  }
     tst := Escape(prdc,STARTDOC,9,'TESTPRINT',NIL); 

     { ********************* CALL THE DLL **********************}
     stretchedoutput(form1.handle, prdc, prnbitmap, mypalette, 0, 0, 1000, 500);

     { tell the printer to print }
     Escape(prdc,NEWFRAME,0,NIL,NIL);
     Escape(prdc,ENDDOC,0,NIL,NIL);
     { clean up }  
     DeleteDC(hmemdc);
     DeleteObject(prnbitmap);
     DeleteDC(prdc);
end;
